package com.ruoyi.eduManage.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Map;
import java.util.HashMap;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.math.BigDecimal;
import java.math.RoundingMode;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.eduManage.utils.EduDictUtils;
import com.ruoyi.common.core.domain.entity.SysDictData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.eduManage.domain.EduClass;
import com.ruoyi.eduManage.domain.EduStudent;
import com.ruoyi.eduManage.mapper.EduHomeworkSubmitMapper;
import com.ruoyi.eduManage.domain.EduHomeworkSubmit;
import com.ruoyi.eduManage.domain.vo.EduHomeworkSubmitImportVo;
import com.ruoyi.eduManage.domain.vo.EduHomeworkSubmitVO;
import com.ruoyi.eduManage.domain.vo.HomeworkImportResultVO;
import com.ruoyi.eduManage.service.IEduClassService;
import com.ruoyi.eduManage.service.IEduHomeworkSubmitService;
import com.ruoyi.eduManage.service.IEduStudentService;
import com.ruoyi.eduManage.service.IEduStudentPointsLogService;
import org.apache.commons.lang3.StringUtils;

/**
 * 作业提交记录Service业务层处理
 *
 * @author ruoyi
 * @date 2025-10-27
 */
@Service
public class EduHomeworkSubmitServiceImpl implements IEduHomeworkSubmitService
{
    private static final Logger log = LoggerFactory.getLogger(EduHomeworkSubmitServiceImpl.class);
    @Autowired
    private EduHomeworkSubmitMapper eduHomeworkSubmitMapper;

    @Autowired
    private IEduStudentService eduStudentService;

    @Autowired
    private IEduClassService eduClassService;

    @Autowired
    private IEduStudentPointsLogService pointsLogService;

    /**
     * 查询作业提交记录
     *
     * @param submitId 作业提交记录主键
     * @return 作业提交记录
     */
    @Override
    public EduHomeworkSubmit selectEduHomeworkSubmitBySubmitId(Long submitId)
    {
        return eduHomeworkSubmitMapper.selectEduHomeworkSubmitBySubmitId(submitId);
    }


    /**
     * 新增作业提交记录
     *
     * @param eduHomeworkSubmit 作业提交记录
     * @return 结果
     */
    @Override
    public int insertEduHomeworkSubmit(EduHomeworkSubmit eduHomeworkSubmit)
    {
        eduHomeworkSubmit.setCreateTime(DateUtils.getNowDate());
        // 从submitDatetime提取日期到submitDate
        if (eduHomeworkSubmit.getSubmitDatetime() != null)
        {
            // 使用SimpleDateFormat提取日期部分
            String dateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, eduHomeworkSubmit.getSubmitDatetime());
            eduHomeworkSubmit.setSubmitDate(DateUtils.parseDate(dateStr));
        }

        // 检查是否已存在相同学号和应交日期的记录
        if (checkSubmitExists(eduHomeworkSubmit.getStudentNo(), eduHomeworkSubmit.getDueDate()))
        {
            throw new ServiceException("该学生在当天已有作业提交记录，不允许重复提交");
        }

        // 根据红花数计算分数
        if (eduHomeworkSubmit.getRedFlowerCount() != null)
        {
            eduHomeworkSubmit.setScore(computeScoreFromRedFlower(eduHomeworkSubmit.getRedFlowerCount()));
        }

        return eduHomeworkSubmitMapper.insertEduHomeworkSubmit(eduHomeworkSubmit);
    }

    /**
     * 修改作业提交记录
     *
     * @param eduHomeworkSubmit 作业提交记录
     * @return 结果
     */
    @Override
    public int updateEduHomeworkSubmit(EduHomeworkSubmit eduHomeworkSubmit)
    {
        eduHomeworkSubmit.setUpdateTime(DateUtils.getNowDate());
        // 从submitDatetime提取日期到submitDate
        if (eduHomeworkSubmit.getSubmitDatetime() != null)
        {
            // 使用SimpleDateFormat提取日期部分
            String dateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, eduHomeworkSubmit.getSubmitDatetime());
            eduHomeworkSubmit.setSubmitDate(DateUtils.parseDate(dateStr));
        }
        // 根据红花数计算分数（更新时亦保持一致逻辑）
        if (eduHomeworkSubmit.getRedFlowerCount() != null)
        {
            eduHomeworkSubmit.setScore(computeScoreFromRedFlower(eduHomeworkSubmit.getRedFlowerCount()));
        }
        return eduHomeworkSubmitMapper.updateEduHomeworkSubmit(eduHomeworkSubmit);
    }

    /**
     * 批量删除作业提交记录
     *
     * @param submitIds 需要删除的作业提交记录主键
     * @return 结果
     */
    @Override
    public int deleteEduHomeworkSubmitBySubmitIds(Long[] submitIds)
    {
        return eduHomeworkSubmitMapper.deleteEduHomeworkSubmitBySubmitIds(submitIds);
    }

    /**
     * 删除作业提交记录信息
     *
     * @param submitId 作业提交记录主键
     * @return 结果
     */
    @Override
    public int deleteEduHomeworkSubmitBySubmitId(Long submitId)
    {
        return eduHomeworkSubmitMapper.deleteEduHomeworkSubmitBySubmitId(submitId);
    }

    /**
     * 将作业提交记录转换为VO对象
     *
     * @param eduHomeworkSubmit 作业提交记录
     * @return 作业提交记录VO
     */
    @Override
    public EduHomeworkSubmitVO convertToVO(EduHomeworkSubmit eduHomeworkSubmit)
    {
        if (eduHomeworkSubmit == null)
        {
            return null;
        }

        EduHomeworkSubmitVO vo = new EduHomeworkSubmitVO();
        BeanUtils.copyProperties(eduHomeworkSubmit, vo);

        // 映射submitGrade到submitGradeName
        if (StringUtils.isNotEmpty(vo.getGrade()))
        {
            String gradeName = EduDictUtils.getDictLabel("submit_grade", vo.getGrade());
            vo.setSubmitGradeName(StringUtils.isNotEmpty(gradeName) ? gradeName : vo.getGrade());
        }

        // 映射submitStatus
        if (StringUtils.isNotEmpty(vo.getSubmitStatus()))
        {
            String statusName = EduDictUtils.getDictLabel("submit_status", vo.getSubmitStatus());
            if (StringUtils.isNotEmpty(statusName))
            {
                vo.setRemark(vo.getSubmitStatus()); // 保存原始状态码到备注
                vo.setSubmitStatus(statusName);
            }
        }

        return vo;
    }

    /**
     * 将作业提交记录列表转换为VO对象列表
     *
     * @param list 作业提交记录列表
     * @return 作业提交记录VO列表
     */
    @Override
    public List<EduHomeworkSubmitVO> convertToVOList(List<EduHomeworkSubmit> list)
    {
        List<EduHomeworkSubmitVO> voList = new ArrayList<>();
        if (list == null || list.isEmpty())
        {
            return voList;
        }

        for (EduHomeworkSubmit submit : list)
        {
            EduHomeworkSubmitVO vo = convertToVO(submit);
            if (vo != null)
            {
                voList.add(vo);
            }
        }

        return voList;
    }


    /**
     * 查询作业提交记录列表
     *
     * @param eduHomeworkSubmit 作业提交记录
     * @return 作业提交记录
     */
    @Override
    public List<EduHomeworkSubmit> selectEduHomeworkSubmitList(EduHomeworkSubmit eduHomeworkSubmit)
    {
        return eduHomeworkSubmitMapper.selectEduHomeworkSubmitList(eduHomeworkSubmit);
    }

    /**
     * 检查作业提交记录是否已存在
     *
     * @param studentNo 学号
     * @param submitDate 提交日期
     * @return true: 存在, false: 不存在
     */
    private boolean checkSubmitExists(String studentNo, Date dueDate)
    {
        if (StringUtils.isEmpty(studentNo) || dueDate == null)
        {
            return false;
        }

        EduHomeworkSubmit query = new EduHomeworkSubmit();
        query.setStudentNo(studentNo);
        // 改为按应交日期检查是否存在
        query.setDueDate(dueDate);
        List<EduHomeworkSubmit> existList = eduHomeworkSubmitMapper.selectEduHomeworkSubmitList(query);
        return existList != null && !existList.isEmpty();
    }
    @Override
    public HomeworkImportResultVO importHomeworkSubmit(MultipartFile file, String classCode, String dueDate)
    {
        HomeworkImportResultVO result = new HomeworkImportResultVO();
        result.setSuccessCount(0);
        result.setFailCount(0);
        result.setFailRecords(new ArrayList<>());
//        String fileName = file.getOriginalFilename();
//        // 1. 文件名格式校验
//        Pattern pattern = Pattern.compile("^(\\d{3})_作业提交记录\\.(xlsx|xls)$");
//        Matcher matcher = pattern.matcher(fileName);
//        if (!matcher.matches()) {
//            result.setErrorMsg("文件名格式不正确，请使用'xxx_作业提交记录.xlsx'格式，其中xxx为3位班级编码");
//            return result;
//        }

        // 2. 提取班级编码并校验班级是否存在
        //String classCode = matcher.group(1);
        String className = "";
        EduClass eduClass = new EduClass();
        eduClass.setClassCode(classCode);
        List<EduClass> classList = eduClassService.selectEduClassList(eduClass);
        if (classList == null || classList.isEmpty()) {
            result.setErrorMsg("班级不存在，导入失败");
            return result;
        } else {
            className = classList.get(0).getClassName();
        }

        try {
            // 解析应交日期（统一应用于本次导入的所有记录）
            Date parsedDueDate = null;
            if (!StringUtils.isEmpty(dueDate)) {
                parsedDueDate = DateUtils.parseDate(dueDate);
            }
            // 使用ExcelUtil读取Excel文件
            ExcelUtil<EduHomeworkSubmitImportVo> util = new ExcelUtil<>(EduHomeworkSubmitImportVo.class);
            List<EduHomeworkSubmitImportVo> importList = util.importExcel(file.getInputStream());

            if (importList == null || importList.isEmpty()) {
                return result;
            }

            for (EduHomeworkSubmitImportVo importVo : importList) {
                try {
                    // 查询学生信息
                    EduStudent student = new EduStudent();
                    student.setStudentName(importVo.getStudentName());
                    student.setClassId(classCode);
                    student.setDelFlag("0");
                    List<EduStudent> studentList = eduStudentService.selectEduStudentList(student);

                    if (studentList == null || studentList.isEmpty()) {
                        // 学生不存在，记录失败
                        HomeworkImportResultVO.FailRecord failRecord = new HomeworkImportResultVO.FailRecord();
                        failRecord.setStudentNo(importVo.getStudentNo());
                        failRecord.setStudentName(importVo.getStudentName());
                        failRecord.setReason("学生信息不存在");
                        result.getFailRecords().add(failRecord);
                        result.setFailCount(result.getFailCount() + 1);
                        continue;
                    }

                    EduStudent existStudent = studentList.get(0);

                    // 3. 创建作业提交记录
                    EduHomeworkSubmit homeworkSubmit = new EduHomeworkSubmit();
                    homeworkSubmit.setStudentNo(existStudent.getStudentNo());
                    homeworkSubmit.setStudentName(existStudent.getStudentName());
                    homeworkSubmit.setClassCode(classCode);
                    homeworkSubmit.setClassName(className);
                    homeworkSubmit.setSubmitContent(importVo.getSubmitContent());
                    homeworkSubmit.setSubmitComment(importVo.getSubmitComment());
                    // 红花数导入并计算分数
                    homeworkSubmit.setRedFlowerCount(importVo.getRedFlowerCount());
                    homeworkSubmit.setScore(computeScoreFromRedFlower(importVo.getRedFlowerCount()));
                    // 磨耳朵时长（字符串）
                    homeworkSubmit.setListenDuration(importVo.getListenDuration());
                    // 设置应交日期（来自导入参数）
                    if (parsedDueDate != null) {
                        homeworkSubmit.setDueDate(parsedDueDate);
                    }

                    // 4. 处理等级映射
                    if (!StringUtils.isEmpty(importVo.getGrade())) {
                        String gradeKey = EduDictUtils.getDictValue("submit_grade", importVo.getGrade());
                        homeworkSubmit.setGrade(StringUtils.isEmpty(gradeKey) ? importVo.getGrade() : gradeKey);
                    }

                    // 5. 处理作业状态映射
                    if (!StringUtils.isEmpty(importVo.getSubmitStatus())) {
                        String statusKey = EduDictUtils.getDictValue("submit_status", importVo.getSubmitStatus());
                        homeworkSubmit.setSubmitStatus(StringUtils.isEmpty(statusKey) ? "0" : statusKey);

                        // 6. 如果作业状态不为空且不是"未交"，则记录提交日期和时间
                        if (!StringUtils.isEmpty(homeworkSubmit.getSubmitStatus()) &&
                                !"0".equals(homeworkSubmit.getSubmitStatus())) {
                            // 设置提交时间
                            if (importVo.getSubmitDatetime() != null) {
                                homeworkSubmit.setSubmitDatetime(importVo.getSubmitDatetime());
                                // 从提交时间中提取日期部分
                                String dateStr = DateUtils.parseDateToStr("yyyy-MM-dd", importVo.getSubmitDatetime());
                                homeworkSubmit.setSubmitDate(DateUtils.parseDate(dateStr));
                            } else {
                                // 如果没有提供提交时间，使用当前时间
                                homeworkSubmit.setSubmitDatetime(DateUtils.getNowDate());
                                homeworkSubmit.setSubmitDate(DateUtils.getNowDate());
                            }
                        }
                    } else {
                        // 默认为未交
                        homeworkSubmit.setSubmitStatus("0");
                    }

                    // 如果提交日期超过应交日期，则标记为迟交（2）
                    if (homeworkSubmit.getDueDate() != null && homeworkSubmit.getSubmitDate() != null) {
                        if (homeworkSubmit.getSubmitDate().after(homeworkSubmit.getDueDate())) {
                            homeworkSubmit.setSubmitStatus("2");
                        }
                    }

                    // 7. 设置创建时间
                    homeworkSubmit.setCreateTime(DateUtils.getNowDate());

                    // 8. 按应交日期检查是否存在重复提交
                    if (checkSubmitExists(homeworkSubmit.getStudentNo(), homeworkSubmit.getDueDate())) {
                        // 记录失败
                        HomeworkImportResultVO.FailRecord failRecord = new HomeworkImportResultVO.FailRecord();
                        failRecord.setStudentNo(homeworkSubmit.getStudentNo());
                        failRecord.setStudentName(homeworkSubmit.getStudentName());
                        failRecord.setReason("该学生在当天已有作业提交记录，跳过导入");
                        result.getFailRecords().add(failRecord);
                        result.setFailCount(result.getFailCount() + 1);
                        continue;
                    }

                    // 9. 保存作业提交记录
                    eduHomeworkSubmitMapper.insertEduHomeworkSubmit(homeworkSubmit);
                    result.setSuccessCount(result.getSuccessCount() + 1);

                    // 10. 将分数同步到学生积分并记录积分变更日志
                    if (homeworkSubmit.getScore() != null) {
                        int deltaPoints = homeworkSubmit.getScore().intValue();
                        if (deltaPoints != 0) {
                            int beforePoints = existStudent.getPoints() == null ? 0 : existStudent.getPoints();
                            existStudent.setPoints(beforePoints + deltaPoints);
                            // 设置日志原因为“作业提交导入”，学生服务将据此写入对应积分日志
                            existStudent.setRemark("作业提交导入");
                            // 设置操作人，便于在日志中记录
                            existStudent.setUpdateBy(SecurityUtils.getUsername());
                            // 使用学生服务进行更新，学生服务内会自动记录积分变更日志
                            eduStudentService.updateEduStudent(existStudent);
                        }
                    }

                } catch (Exception e) {
                    log.error("数据导入失败",e);
                    // 处理异常，记录失败
                    HomeworkImportResultVO.FailRecord failRecord = new HomeworkImportResultVO.FailRecord();
                    failRecord.setStudentNo(importVo.getStudentNo());
                    failRecord.setStudentName(importVo.getStudentName());
                    failRecord.setReason("导入异常: " + e.getMessage());
                    result.getFailRecords().add(failRecord);
                    result.setFailCount(result.getFailCount() + 1);
                }
            }

        } catch (Exception e) {
            throw new RuntimeException("导入Excel异常: " + e.getMessage());
        }

        return result;
    }

    /**
     * 根据红花数计算分数：固定 1 朵红花 = 5 分
     */
    private Long computeScoreFromRedFlower(Long redFlowerCount) {
        if (redFlowerCount == null) {
            return null;
        }
        return redFlowerCount.longValue() * 5;
    }

    @Override
    public Map<String, Object> getDailySubmitDetailData(String startDate, String endDate, String classCode, Integer expectedDays) {
        Map<String, Object> result = new HashMap<>();

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date start = sdf.parse(startDate);
            Date end = sdf.parse(endDate);

            // 获取班级信息
            EduClass eduClass = new EduClass();
            eduClass.setClassCode(classCode);
            List<EduClass> classList = eduClassService.selectEduClassList(eduClass);
            if (classList.isEmpty()) {
                result.put("success", false);
                result.put("message", "班级不存在");
                return result;
            }
            EduClass classInfo = classList.get(0);

            // 获取班级学生列表
            EduStudent studentQuery = new EduStudent();
            studentQuery.setClassId(classCode);
            List<EduStudent> students = eduStudentService.selectEduStudentList(studentQuery);

            // 生成日期列表
            List<String> dateColumns = new ArrayList<>();
            Calendar cal = Calendar.getInstance();
            cal.setTime(start);
            while (!cal.getTime().after(end)) {
                dateColumns.add(sdf.format(cal.getTime()));
                cal.add(Calendar.DAY_OF_MONTH, 1);
            }

            // 获取提交记录
            EduHomeworkSubmit submitQuery = new EduHomeworkSubmit();
            submitQuery.setClassCode(classCode);
            submitQuery.setSubmitDate(start);
            List<EduHomeworkSubmit> submits = eduHomeworkSubmitMapper.selectEduHomeworkSubmitList(submitQuery);

            // 按学号和日期组织数据
            Map<String, Map<String, String>> studentSubmitMap = new HashMap<>();
            for (EduHomeworkSubmit submit : submits) {
                String submitDateStr = sdf.format(submit.getSubmitDate());
                if (dateColumns.contains(submitDateStr)) {
                    studentSubmitMap.computeIfAbsent(submit.getStudentNo(), k -> new HashMap<>())
                        .put(submitDateStr, "已提交");
                }
            }

            // 构建学生数据
            List<Map<String, Object>> studentData = new ArrayList<>();
            int totalSubmissions = 0;
            int submittedCount = 0;

            for (EduStudent student : students) {
                Map<String, Object> studentInfo = new HashMap<>();
                studentInfo.put("studentNo", student.getStudentNo());
                studentInfo.put("studentName", student.getStudentName());
                studentInfo.put("englishName", student.getEnglishName());

                String dailyStatus = null;
                int studentSubmitCount = 0;

                for (String date : dateColumns) {
                    String status = studentSubmitMap.getOrDefault(student.getStudentNo(), new HashMap<>())
                        .getOrDefault(date, "未交");
                    dailyStatus = status;
                    if ("已提交".equals(status)) {
                        studentSubmitCount++;
                    }
                }

                studentInfo.put("dailyStatus", dailyStatus);
                studentInfo.put("totalScore", studentSubmitCount);
                studentData.add(studentInfo);

                totalSubmissions += dateColumns.size();
                submittedCount += studentSubmitCount;
            }

            // 计算出勤率
            double attendanceRate = totalSubmissions > 0 ? (double) submittedCount / totalSubmissions * 100 : 0;

            result.put("success", true);
            result.put("classCode", classCode);
            result.put("className", classInfo.getClassName());
            result.put("dateColumns", dateColumns);
            result.put("studentData", studentData);
            result.put("totalStudents", students.size());
            result.put("totalSubmissions", totalSubmissions);
            result.put("submittedCount", submittedCount);
            result.put("attendanceRate", Math.round(attendanceRate * 100.0) / 100.0);

        } catch (Exception e) {
            log.error("获取每日提交详情失败", e);
            result.put("success", false);
            result.put("message", "获取数据失败: " + e.getMessage());
        }

        return result;
    }

    /**
     * 生成本周积分统计图片（至今日）PNG字节
     */
    @Override
    public byte[] generateWeeklyPointsImage(String date, List<String> classIds) {
        try {
            java.time.LocalDate base = java.time.LocalDate.parse(date);
            java.time.LocalDate today = java.time.LocalDate.now();
            // 计算当周范围：周一至 min(本周周日, 今天)
            java.time.LocalDate weekStart = base.with(java.time.temporal.TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
            java.time.LocalDate endOfWeek = base.with(java.time.temporal.TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
            java.time.LocalDate weekEnd = endOfWeek.isBefore(today) ? endOfWeek : today;

            java.util.List<String> dateColumns = new java.util.ArrayList<>();
            for (java.time.LocalDate d = weekStart; !d.isAfter(weekEnd); d = d.plusDays(1)) {
                dateColumns.add(d.toString());
            }
            // 兜底：若范围为空（例如传入未来日期导致周范围在今天之后），则使用今天作为唯一列
            if (dateColumns.isEmpty()) {
                dateColumns.add(today.toString());
            }

            // 聚合学生
            java.util.List<EduStudent> students = new java.util.ArrayList<>();
            java.util.Set<Long> addedIds = new java.util.HashSet<>();
            if (classIds != null) {
                for (String sid : classIds) {
                    if (sid == null || sid.trim().isEmpty()) continue;
                    EduStudent q = new EduStudent();
                    q.setClassId(sid.trim());
                    java.util.List<EduStudent> batch = eduStudentService.selectEduStudentList(q);
                    if (batch != null) {
                        for (EduStudent s : batch) {
                            if (s.getStudentId() != null && addedIds.add(s.getStudentId())) {
                                students.add(s);
                            }
                        }
                    }
                }
            }

            int leftInfoWidth = 380;
            int dateColWidth = 40;
            int metricColWidth = 70; // 末尾统计列宽
            int metricCount = 4;     // 总提交次、总奖励、打卡率、应打卡
            int rowHeight = 28;
            int headerHeight = 66;
            int legendHeight = 34;
            int padding = 10;
            int rows = students != null ? students.size() : 0;
            int cols = dateColumns.size();
            int width = padding * 2 + leftInfoWidth + Math.max(cols, 1) * dateColWidth + metricCount * metricColWidth;
            int height = padding * 2 + headerHeight + legendHeight + Math.max(rows, 1) * rowHeight;

            java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
            java.awt.Graphics2D g = image.createGraphics();
            g.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(java.awt.Color.WHITE);
            g.fillRect(0, 0, width, height);

            g.setColor(new java.awt.Color(51,51,51));
            g.setFont(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 16));
            g.drawString("学生本周奖励积分统计", padding, padding + 20);
            int legendY = padding + 44;
            g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));
            g.setColor(new java.awt.Color(67,160,71)); g.fillRect(padding, legendY - 10, 14, 14);
            g.setColor(java.awt.Color.DARK_GRAY); g.drawString("有积分(>0)", padding + 20, legendY);
            g.setColor(new java.awt.Color(189,189,189)); g.fillRect(padding + 110, legendY - 10, 14, 14);
            g.setColor(java.awt.Color.DARK_GRAY); g.drawString("无积分(=0)", padding + 130, legendY);

            int headerY = padding + headerHeight - 20;
            int startX = padding + leftInfoWidth;
            g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));
            g.setColor(new java.awt.Color(120,120,120));
            for (int i = 0; i < dateColumns.size(); i++) {
                String dstr = dateColumns.get(i);
                String mmdd = dstr.substring(5).replace("-", ".");
                int x = startX + i * dateColWidth + 6;
                g.drawString(mmdd, x, headerY);
            }
            // 末尾统计列头
            int metricsStartX = startX + cols * dateColWidth;
            String[] metricHeaders = new String[]{"总提交次","总奖励","打卡率","应打卡"};
            for (int i = 0; i < metricHeaders.length; i++) {
                int x = metricsStartX + i * metricColWidth + 6;
                g.drawString(metricHeaders[i], x, headerY);
            }
            g.setColor(new java.awt.Color(230,230,230));
            g.drawLine(padding, padding + headerHeight, width - padding, padding + headerHeight);
            g.setColor(new java.awt.Color(100,100,100));
            g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13));
            g.drawString("学生姓名", padding + 6, padding + headerHeight - 22);
            g.drawString("英文名", padding + 136, padding + headerHeight - 22);
            g.drawString("班级ID", padding + 266, padding + headerHeight - 22);

            int y = padding + headerHeight + legendHeight;
            if (students != null) {
                for (EduStudent stu : students) {
                    g.setColor(new java.awt.Color(33,33,33));
                    g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13));
                    if (stu.getStudentName() != null) g.drawString(stu.getStudentName(), padding + 6, y - 8);
                    if (stu.getEnglishName() != null) g.drawString(stu.getEnglishName(), padding + 136, y - 8);
                    if (stu.getClassId() != null) g.drawString(stu.getClassId(), padding + 266, y - 8);

                    java.util.Map<String,Integer> pointsByDate = new java.util.HashMap<>();
                    // 学生ID为空则跳过查询，全部视为0积分
                    java.util.List<java.util.Map<String,Object>> rowsData = null;
                    if (stu.getStudentId() != null) {
                        rowsData = pointsLogService.selectDailyPointsByStudent(
                                stu.getStudentId(), dateColumns.get(0), dateColumns.get(dateColumns.size()-1));
                    }
                    if (rowsData != null) {
                        for (java.util.Map<String,Object> r : rowsData) {
                            String dkey = String.valueOf(r.get("date"));
                            Integer p = null;
                            Object pv = r.get("points");
                            if (pv instanceof Number) p = ((Number) pv).intValue();
                            else if (pv != null) try { p = Integer.valueOf(pv.toString()); } catch (Exception ignore) {}
                            pointsByDate.put(dkey, p == null ? 0 : p);
                        }
                    }

                    for (int i = 0; i < dateColumns.size(); i++) {
                        String dstr = dateColumns.get(i);
                        int cellX = startX + i * dateColWidth + 6;
                        int cellY = y - rowHeight + 6;
                        int val = pointsByDate.getOrDefault(dstr, 0);
                        java.awt.Color color = val > 0 ? new java.awt.Color(67,160,71) : new java.awt.Color(189,189,189);
                        g.setColor(color);
                        g.fillRoundRect(cellX - 4, cellY - 6, dateColWidth - 12, rowHeight - 12, 6, 6);
                        g.setColor(java.awt.Color.WHITE);
                        g.setFont(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 12));
                        String txt = String.valueOf(val);
                        g.drawString(txt, cellX + (dateColWidth - 12)/2 - (txt.length()*3), cellY + 10);
                    }

                    // 末尾统计列：总提交次、总奖励、打卡率、应打卡
                    int metricsX = metricsStartX;
                    int expectedDays = cols;
                    int totalSubmissions = (rowsData == null) ? 0 : rowsData.size();
                    int totalRewards = 0;
                    for (Integer v : pointsByDate.values()) { totalRewards += (v == null ? 0 : v); }
                    double rate = expectedDays > 0 ? (double) totalSubmissions / (double) expectedDays : 0.0;
                    String rateText = String.format(java.util.Locale.US, "%.1f%%", rate * 100);

                    g.setColor(new java.awt.Color(33,33,33));
                    g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));
                    // 总提交次
                    g.drawString(String.valueOf(totalSubmissions), metricsX + 6, y - rowHeight + 16);
                    // 总奖励
                    metricsX += metricColWidth;
                    g.drawString(String.valueOf(totalRewards), metricsX + 6, y - rowHeight + 16);
                    // 打卡率
                    metricsX += metricColWidth;
                    g.drawString(rateText, metricsX + 6, y - rowHeight + 16);
                    // 应打卡
                    metricsX += metricColWidth;
                    g.drawString(String.valueOf(expectedDays), metricsX + 6, y - rowHeight + 16);

                    g.setColor(new java.awt.Color(240,240,240));
                    g.drawLine(padding, y, width - padding, y);
                    y += rowHeight;
                }
            }

            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            javax.imageio.ImageIO.write(image, "png", baos);
            g.dispose();
            return baos.toByteArray();
        } catch (Exception e) {
            log.error("生成本周积分统计图片失败", e);
            throw new RuntimeException("生成本周积分统计图片失败");
        }
    }

}
